package com.share.common.rabbit.service;


import com.alibaba.fastjson2.JSON;
import com.share.common.rabbit.entity.GuiguCorrelationData;
import lombok.RequiredArgsConstructor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * RabbitMQ消息发送服务类
 * 封装RabbitMQ消息发送的通用方法，支持普通消息和延迟消息的发送
 * 并提供消息追踪和可靠性保障机制
 */
@Service
@RequiredArgsConstructor
public class RabbitService {

    /**
     * RabbitMQ模板类，用于实际发送消息到RabbitMQ服务器
     */
    private final RabbitTemplate rabbitTemplate;

    /**
     * Redis模板类，用于存储消息相关元数据，支持消息重试机制
     */
    private final RedisTemplate redisTemplate;

    /**
     * 发送普通消息
     *
     * @param exchange   目标交换机名称
     * @param routingKey 路由键，用于消息路由到指定队列
     * @param message    消息内容，可以是任意可序列化对象
     * @return 发送操作是否结果，true表示发送成功（仅指消息提交到RabbitMQ客户端，不代表已送达交换机）
     */
    public boolean sendMessage(String exchange, String routingKey, Object message) {
        // 1. 创建自定义关联数据对象，封装包含消息追踪所需需的元数据
        GuiguCorrelationData correlationData = new GuiguCorrelationData();
        // 生成唯一消息ID，格式为"mq:UUID"（去除横杠）
        String uuid = "mq:" + UUID.randomUUID().toString().replaceAll("-", "");
        correlationData.setId(uuid);
        correlationData.setMessage(message);       // 消息内容
        correlationData.setExchange(exchange);     // 目标交换机
        correlationData.setRoutingKey(routingKey); // 路由键

        // 2. 使用RabbitTemplate发送消息，附带关联数据
        rabbitTemplate.convertAndSend(exchange, routingKey, message, correlationData);

        // 3. 将消息关联数据存入Redis，设置10分钟过期时间
        // 用于消息发送失败时的重试机制和状态追踪
        redisTemplate.opsForValue().set(uuid, JSON.toJSONString(correlationData), 10, TimeUnit.MINUTES);

        return true;
    }

    /**
     * 发送延迟消息
     * 使用Rabbitmq_delayed_message_exchange插件插件实现实现延迟投递功能
     *
     * @param exchange   目标交换机名称（需是x-delayed   ayed_message类型）
     * @param routingKey 路由键，用于消息路由到指定队列
     * @param message    消息内容，可以是任意可序列化对象
     * @param delayTime  延迟时间，单位为秒
     * @return 发送操作的结果，true表示发送成功
     */
    public boolean sendDealyMessage(String exchange, String routingKey, Object message, int delayTime) {
        // 1. 创建自定义定义关联数据对象，标记为延迟消息
        GuiguCorrelationData correlationData = new GuiguCorrelationData();
        String uuid = "mq:" + UUID.randomUUID().toString().replaceAll("-", "");
        correlationData.setId(uuid);
        correlationData.setMessage(message);       // 消息内容
        correlationData.setExchange(exchange);     // 目标交换机
        correlationData.setRoutingKey(routingKey); // 路由键
        correlationData.setDelay(true);             // 标记为延迟消息
        correlationData.setDelayTime(delayTime);   // 延迟时间（秒）

        // 2. 发送延迟消息，通过messageetterperties.set设置消息延迟属性
        rabbitTemplate.convertAndSend(
                exchange,
                routingKey,
                message,
                // 消息后置处理器：设置延迟时间（转换为毫秒）
                message1 -> {
                    message1.getMessageProperties().setDelay(delayTime * 1000);
                    return message1;
                },
                correlationData
        );

        // 3. 将延迟消息的关联数据存入Redis，设置10分钟过期时间
        redisTemplate.opsForValue().set(uuid, JSON.toJSONString(correlationData), 10, TimeUnit.MINUTES);

        return true;
    }
}